package study.domain.attachment;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import java.util.regex.Pattern;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Setter;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.Index;
import org.hibernate.annotations.Table;
import org.hibernate.validator.constraints.NotEmpty;

import study.domain.user.User;

import com.barney.support.domain.HasCreatedDate;
import com.barney.support.jpa.CreatedDateListener;

/**
 * 첨부 파일
 *
 * @author Barney Kim
 */
@Entity(name = "attachments")
@Table(appliesTo = "attachments", indexes = @Index(name = "idx_attachments_group_id",
		columnNames = "group_id"))
@Data
@EqualsAndHashCode(of = { "id" })
@EntityListeners(CreatedDateListener.class)
public class Attachment implements Serializable, HasCreatedDate {

	private static final long serialVersionUID = 4572365555126062160L;

	/**
	 * 이미지 확장자
	 */
	public static final String[] IMAGE_EXTENSIONS = { "gif", "png", "jpg", "jpeg" };

	/**
	 * UUID를 사용한 ID
	 */
	@Id
	@Column(length = 36)
	private String id;

	/**
	 * 한번에 여러 개 파일을 올릴 때 구분하기 위한 그룹 ID
	 */
	@Column(name = "group_id", nullable = false, updatable = false)
	private String groupId;

	/**
	 * 올린 사용자 ID
	 */
	@OneToOne(fetch = FetchType.EAGER)
	@JoinColumn(name = "user_id", nullable = false, updatable = false)
	@org.hibernate.annotations.ForeignKey(name = "fk_attachments_user_id")
	private User user;

	/**
	 * 분류
	 */
	@NotEmpty
	@Column(nullable = false, length = 50, updatable = false)
	private String category;

	/**
	 * 원본 파일명
	 */
	@NotEmpty
	@Column(name = "filename", nullable = false, length = 255, updatable = false)
	private String filename;

	@Column(name = "filesize", nullable = false, updatable = false)
	private long filesize;

	/**
	 * 확장자 명
	 */
	@NotEmpty
	@Setter(value = AccessLevel.NONE)
	@Column(name = "extension", nullable = false, length = 8, updatable = false)
	private String extension;

	/**
	 * 이미지 너비
	 */
	@Column
	private int imageWidth;

	/**
	 * 이미지 높이
	 */
	@Column
	private int imageHeight;

	@Temporal(TemporalType.TIMESTAMP)
	@Column(nullable = false, updatable = false)
	private Date createdDate;

	/**
	 * 원본 파일명을 설정할 때 파일 확장자를 정한다.
	 *
	 * @param filename 원본 파일명
	 */
	public void setFilename(String filename) {
		String tempExtension = FilenameUtils.getExtension(filename);
		if (StringUtils.isBlank(tempExtension)) {
			throw new RuntimeException("No extension for " + filename);
		}
		this.filename = filename;
		this.extension = tempExtension.toLowerCase();
	}

	public boolean isImage() {
		return (ArrayUtils.contains(IMAGE_EXTENSIONS, getExtension()));
	}

	/**
	 * 원본 파일 패스를 반환한다.
	 */
	public String getFilePath() {
		return getFilePath(AttachmentType.ORIGINAL);
	}

	/**
	 * 지정한 종류의 파일 패스를 반환한다.
	 * <p>
	 * 파일 패스 형식 <code>/category/yyyy/MM/file[_type].ext</code>
	 * </p>
	 * 주의: 파일이 이미지가 아니라면 언제나 원본을 사용하고 이미지이고
	 * 원본이 아니면 확장자는 jpg 이다.
	 *
	 * @param type 종류
	 */
	public String getFilePath(AttachmentType type) {
		if (!isImage()) {
			type = AttachmentType.ORIGINAL;
		}
		String postfix = type.getPostfix();
		String ext = extension;
		if (isImage() && type != AttachmentType.ORIGINAL) {
			ext = "jpg";
			postfix = type.getPostfix(imageWidth, imageHeight);
		}
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM");
		String yearMonth = sdf.format(createdDate);
		return String.format("/%s/%s/%s%s.%s",
				category, yearMonth, id, postfix, ext);
	}

	public static String generateUuid() {
		return UUID.randomUUID().toString();
	}

	public static boolean isUuid(String uuid) {
		String regex = "\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}";
		return Pattern.matches(regex, uuid);
	}

	public String getUrl() {
		return getUrl(AttachmentType.ORIGINAL);
	}

	public String getThumbnailUrl() {
		return getUrl(AttachmentType.IMAGE_SMALL);
	}

	public String getUrl(AttachmentType type) {
		return String.format("%s%s", "/attachments", getFilePath(type));
	}
}
